/**
 *  Copyright (C) 2014 lixlee
 *
 *  This software is provided 'as-is', without any express or implied
 *  warranty.  In no event will the authors be held liable for any damages
 *  arising from the use of this software.
 *
 *  Permission is granted to anyone to use this software for any purpose,
 *  including commercial applications, and to alter it and redistribute it
 *  freely, subject to the following restrictions:
 *
 *  1. The origin of this software must not be misrepresented; you must not
 *     claim that you wrote the original software. If you use this software
 *     in a product, an acknowledgment in the product documentation would be
 *     appreciated but is not required.
 *  2. Altered source versions must be plainly marked as such, and must not be
 *     misrepresented as being the original software.
 *  3. This notice may not be removed or altered from any source distribution.
 *
 */
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "../include/base64.h"

#ifndef BOOL
#define BOOL int
#define TRUE 1
#define FALSE 0
#endif

void cmd_base32_encode(char* s, int len)
{
    char* base_code = base32_encode(s,len);
    if(base_code){
        fprintf(stdout,"base32: %s\n",base_code);
        free(base_code);
    }
}

void cmd_base32_decode(char* s, int len)
{
    int n = 0;
    char* base_code = base32_decode(s,len,NULL,&n);
    if(base_code){
        fprintf(stdout,"text(%d): %s\n",n,base_code);
        free(base_code);
    }
}

void cmd_base64_encode(char* s, int len)
{
    char* base_code = base64_encode(s,len);
    if(base_code){
        fprintf(stdout,"base64: %s\n",base_code);
        free(base_code);
    }
}

void cmd_base64_decode(char* s, int len)
{
    int n = 0;
    char* base_code = base64_decode(s,len,NULL,&n);
    if(base_code){
        fprintf(stdout,"text(%d): %s\n",n,base_code);
        free(base_code);
    }
}

void print_usage(const char* name)
{
    const char* p = name;
    while(p && *p){
        if(*p == '/'){
            name = p + 1;
        }
        p++;
    }
    name = name ? name : "base64";

    fprintf(stdout,
    "Usage: %s command  [ command_opts ] [ command_args ]\n", name);

    fprintf(stdout,
    "       %s base64 <text>            Encode text into base64 coding\n"
    "       %s base64 --encode <text>   Encode text into base64 coding\n"
    "       %s base64 --decode <text>   Decode base64 coded text\n"

    "       %s base32 <text>            Encode text into base32 coding\n"
    "       %s base32 --encode <text>   Encode text into base32 coding\n"
    "       %s base32 --decode <text>   Decode base32 coded text\n"

    ,name,name,name,name,name,name
    );
}

#define CMD_UNDEFINED -1

#define CMD_BASE64_ENCODE 0x10
#define CMD_BASE64_DECODE 0x11

#define CMD_BASE32_ENCODE 0x20
#define CMD_BASE32_DECODE 0x21

int main(int argc, char** argv)
{
    int cmd = CMD_UNDEFINED;

    if(argc < 2){
        print_usage(argv[0]);
        return 0;
    }else if(argc >= 2){
        if(0 == strcmp("-h",argv[1]) || 0 == strcmp("--help",argv[1]) || 0 == strcmp("help",argv[1])){
            print_usage(argv[0]);
            return 0;
        }else if(0 == strcmp("base32",argv[1])){
            cmd = CMD_BASE32_ENCODE;
        }else if(0 == strcmp("base64",argv[1])){
            cmd = CMD_BASE64_ENCODE;
        }
    }

    if(cmd == CMD_UNDEFINED){
        fprintf(stderr,"Error: '%s' is an invalid command.",argv[1]);
        return 0;
    }

    char* text = NULL;
    BOOL opt_encode = FALSE;
    BOOL opt_decode = FALSE;

    int i;
    int idx = 2;
    for(i = idx; i < argc; i++){
        if(0 == strcmp("-e",argv[i]) || 0 == strcmp("--encode",argv[i])){
            opt_encode = TRUE;
        }else if(0 == strcmp("-d",argv[i]) || 0 == strcmp("--decode",argv[i])){
            opt_decode = TRUE;
        }

        if(0 == strncmp("-",argv[i],1))
            idx = i + 1;
    }

    if(opt_encode && opt_decode){
        fprintf(stderr,"Error: Cannot specify options '-e,--encode' and '-d,--decode' at the same time.");
        return 0;
    }
    if(opt_decode){
        cmd |= 0x1;
    }

    if(idx < argc)
    {
        text = strdup(argv[idx]);
    }else{
        int maxsize = 2*1024*1024;
        text = malloc(maxsize);
        memset(text,0,maxsize);
        char ch = getchar();
        i = 0;
        while(ch != EOF && i < maxsize - 1){
            text[i] = ch;
            i++;
        }
    }

    if(text) {
        switch(cmd)
        {
        case CMD_BASE32_ENCODE:
            {
                cmd_base32_encode(text,strlen(text));
            }
            break;
        case CMD_BASE32_DECODE:
            {
                cmd_base32_decode(text,strlen(text));
            }
            break;
        case CMD_BASE64_ENCODE:
            {
                cmd_base64_encode(text,strlen(text));
            }
            break;
        case CMD_BASE64_DECODE:
            {
                cmd_base64_decode(text,strlen(text));
            }
            break;
        default:
            break;
        }
    }

    if(text){
        free(text);
    }
    return 0;
}
